/******************************************************/
/* Goblin's Cube - Rubik's cube game for Wii Homebrew */
/* Copyright (C) 2009 Ricardo Bueno Cordeiro          */
/* Licensed under de GNU General Public License v2.0  */
/*   See license_gplv2.txt for detalis                */
/******************************************************/

#include <asndlib.h>
#include <malloc.h>
#include <string.h>

#include "sound.h"

void sound_init() {
	ASND_Init();
}

void sound_end() {
	ASND_End();
}

Sound::Sound() {
	this->state = SOUND_STATE_UNLOADED;
	this->format = 0;
	this->pitch = 0;
	this->size = 0;
	this->aligned_samples = NULL;
	this->sound_loader = NULL;
}

Sound::~Sound() {
	this->unload();
}

void Sound::play(s32 delay, s32 sl, s32 sr) {
	s32 free_voice = ASND_GetFirstUnusedVoice();
	if ((free_voice == SND_INVALID) || (free_voice < 1))
		return;

	if (ASND_Is_Paused())
		ASND_Pause(0);

	ASND_SetVoice(free_voice, this->format, this->pitch, delay, this->aligned_samples, this->size, sl, sr, NULL);
}

void Sound::load(SoundLoader *sl) {
	if (this->state == SOUND_STATE_LOADED)
		this->unload();

	this->sound_loader = sl;

	this->size = this->sound_loader->get_size();
	this->pitch = this->sound_loader->get_pitch();

	u16 bits = this->sound_loader->get_num_bits_per_sample();
	u16 num_channel = this->sound_loader->get_num_channel();
	
	// Set data format, if valid
	if (bits == 8) {
		switch (num_channel) {
			case 1: this->format = VOICE_MONO_8BIT; break;
			case 2: this->format = VOICE_STEREO_8BIT; break;
			default: return; // this will let the state as unloaded
		}
	} else if (bits == 16) {
		switch (num_channel) {
			case 1: this->format = VOICE_MONO_16BIT; break;
			case 2: this->format = VOICE_STEREO_16BIT; break;
			default: return; // this will let the state as unloaded
		}
	} else
		return; // this will let the state as unloaded

	// Allocate 32 bytes aligned and padded buffer
	u32 padded_size = (this->size & ~0x1f) + 0x20;
	this->aligned_samples = memalign(32, padded_size);
	memset(this->aligned_samples, 0, padded_size);
	
	this->sound_loader->get_samples(this->aligned_samples, 0, this->size);
	this->state = SOUND_STATE_LOADED;
}

void Sound::unload() {
	if (this->aligned_samples != NULL)
		free(this->aligned_samples);
	
	this->state = SOUND_STATE_UNLOADED;
	this->format = 0;
	this->pitch = 0;
	this->size = 0;
	this->aligned_samples = NULL;
	
	if (this->sound_loader != NULL)
		delete this->sound_loader;
}
